package com.platform.template.qiniu;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.text.MessageFormat;

import javax.annotation.PostConstruct;

import com.google.gson.reflect.TypeToken;
import com.platform.common.utils.Assert;
import com.platform.common.utils.GsonUtils;
import com.platform.common.utils.HttpUtils;
import com.platform.template.qiniu.VideoInfo.SelfVideoInfo;
import com.qiniu.cdn.CdnManager;
import com.qiniu.common.QiniuException;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.processing.OperationManager;
import com.qiniu.processing.OperationStatus;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.BucketManager.FileListIterator;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.util.Auth;
import com.qiniu.util.UrlSafeBase64;

/**
 * <pre>
 * 功能：七牛服务
 * 
 * &lt;bean id="qiniuOssService" class="com.platform.template.qiniu.QiniuOSSTemplate"&gt;
 * 		&lt;property name="accessKey" value="${qiniu.accessKey}" /&gt;
 * 		&lt;property name="secretKey" value="${qiniu.secretKey}" /&gt;
 * 		&lt;property name="pipeline" value="${qiniu.pipeline}" /&gt;
 * &lt;/bean&gt;
 * 
 * 在properties文件中配置：
 * qiniu.endpoint
 * qiniu.accessKey
 * qiniu.secretKey
 * 
 * </pre>
 * 
 * @author wei.gao
 */
public class QiniuOSSTemplate {
	private String accessKey = null;
	private String secretKey = null;
	private String pipeline = null;
	
	@PostConstruct
	private void init(){
		Assert.notEmpty("accessKey", accessKey);
		Assert.notEmpty("secretKey", secretKey);
		Assert.notEmpty("pipeline", pipeline);
	}
	
	// 认证对象
	private Auth auth = null;
	// 创建上传对象
	private UploadManager uploadManager = null;
	// 创建管理对象
	private BucketManager bucketManager = null;
	// 创建操作对象
	private OperationManager operaterManager = null;
	// 创建Cdn对象
	private CdnManager cdn = null;
	
	/**
	 * <pre>
	 * 功能：简单上传，使用默认策略，只需要设置上传的空间名就可以了
	 * </pre>
	 * 
	 * @param bucketName
	 * @return
	 */
	public String getUploadToken(String bucketName) {
		return getAuth().uploadToken(bucketName);
	}
	
	/**
	 * <pre>
	 * 功能：上传流
	 * </pre>
	 * 
	 * @param bucketName
	 * @param key
	 * @param stream
	 * @return
	 * @throws Exception
	 */
	public Response upload(String bucketName, String key, InputStream stream) throws Exception {
		// 调用put方法上传
		Response res = getUploadManager().put(stream, key, getUploadToken(bucketName), null, null);
		// 打印返回的信息
		return res;
	}
	
	/**
	 * <pre>
	 * 功能：上传字节流
	 * </pre>
	 * 
	 * @param bucketName
	 * @param key
	 * @param data
	 * @return
	 * @throws Exception
	 */
	public Response upload(String bucketName, String key, byte[] data) throws Exception {
		// 调用put方法上传
		Response res = getUploadManager().put(data, key, getUploadToken(bucketName));
		// 打印返回的信息
		return res;
	}
	
	/**
	 * <pre>
	 * 功能：上传文件
	 * </pre>
	 * 
	 * @param bucketName
	 * @param key
	 * @param file
	 * @return
	 * @throws Exception
	 */
	public Response upload(String bucketName, String key, File file) throws Exception {
		// 调用put方法上传
		Response res = getUploadManager().put(file, key, getUploadToken(bucketName));
		// 打印返回的信息
		return res;
	}
	
	/**
	 * <pre>
	 * 功能：获取指定key的文件信息
	 * </pre>
	 * 
	 * @param bucketName
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public FileInfo getFileInfo(String bucketName, String key) throws Exception {
		return getBucketManager().stat(bucketName, key);
	}
	
	/**
	 * <pre>
	 * 功能：视频做压缩及加水印处理
	 * </pre>
	 * 
	 * @param bucketName
	 * @param key
	 * @param watermark
	 * @param newKey
	 * @return
	 * @throws Exception
	 */
	public String mp4process(String bucketName, String key, String watermark, String newKey) throws Exception {
		// 可以对转码后的文件进行使用saveas参数自定义命名，当然也可以不指定文件会默认命名并保存在当前空间。
		String urlbase64 = UrlSafeBase64.encodeToString(bucketName + ":" + newKey);
		String urlbase641 = UrlSafeBase64.encodeToString(watermark);
		String mp4 = MessageFormat.format("avthumb/mp4/wmImage/{0}/wmGravity/NorthEast/wmOffsetX/0/wmOffsetY/0", urlbase641);
		String pfops = mp4 + "|saveas/" + urlbase64;
		// 设置pipeline参数
		String persistentId = getOperaterManager().pfop(bucketName, key, pfops, pipeline, true);
		return persistentId;
	}
	
	/**
	 * <pre>
	 * 功能：获取视频第一帧做缩略图
	 * </pre>
	 * 
	 * @param bucketName
	 * @param key
	 * @param newKey
	 * @return
	 * @throws Exception
	 */
	public String getVideoCover(String bucketName, String key, String newKey) throws Exception {
		// 设置转码操作参数
		String fops = "vframe/jpg/offset/0";
		// 可以对转码后的文件进行使用saveas参数自定义命名，当然也可以不指定文件会默认命名并保存在当前空间。
		String urlbase64 = UrlSafeBase64.encodeToString(bucketName + ":" + newKey);
		String pfops = fops + "|saveas/" + urlbase64;
		// 设置pipeline参数
		String persistentId = getOperaterManager().pfop(bucketName, key, pfops, pipeline, true);
		return persistentId;
	}
	
	/**
	 * <pre>
	 * 功能：获取图片的缩略图
	 * </pre>
	 * 
	 * @param key
	 * @param newKey
	 * @return
	 * @throws Exception
	 */
	public String getImageCover(String bucketName, String key, String newKey) throws Exception {
		// 设置转码操作参数
		String fops = "imageMogr2/auto-orient/thumbnail/596x>/blur/1x0/quality/75";
		// 可以对转码后的文件进行使用saveas参数自定义命名，当然也可以不指定文件会默认命名并保存在当前空间。
		String urlbase64 = UrlSafeBase64.encodeToString(bucketName + ":" + newKey);
		String pfops = fops + "|saveas/" + urlbase64;
		// 设置pipeline参数
		String persistentId = getOperaterManager().pfop(bucketName, key, pfops, pipeline, true);
		return persistentId;
	}
	
	/**
	 * <pre>
	 * 功能：图片压缩及水印处理
	 * 小于4M的不压缩，大于4M的按80%质量压缩
	 * 水印竖屏的ws=0.3，横屏的ws=0.1
	 * </pre>
	 * @param bucketName
	 * @param basePath
	 * @param key
	 * @param watermark
	 * @param newKey
	 * @return
	 * @throws Exception
	 */
	public String imageProcess(String bucketName, String basePath, String key, String watermark, String newKey) throws Exception {
		String imageProcess = "";
		ImageInfo old = getImageInfo(basePath, key);
		// 判断竖屏还是横屏
		if (old.width < old.height) {
			imageProcess += "watermark/1/image/{0}/dissolve/100/gravity/South/dx/0/dy/0/ws/0.3";
		} else {
			imageProcess += "watermark/1/image/{0}/dissolve/100/gravity/South/dx/0/dy/0/ws/0.1";
		}
		// 判断是否压缩
		if (old.size > 4 * 1024 * 1024) {
			// 4M以上压缩
			imageProcess += "|imageMogr2/auto-orient/quality/80!";
		}
		String bucket = UrlSafeBase64.encodeToString(bucketName + ":" + newKey);
		String urlbase641 = UrlSafeBase64.encodeToString(watermark);
		String image = MessageFormat.format(imageProcess, urlbase641);
		String pfops = image + "|saveas/" + bucket;
		//设置pipeline参数
		String persistentId = getOperaterManager().pfop(bucketName, key, pfops, pipeline, true);
		return persistentId;
	}
	
	/**
	 * <pre>
	 * 功能：等待fops处理完成
	 * http://api.qiniu.com/status/get/prefop?id=z2.5a1ffe5de3d0041bf82c2c03
	 * </pre>
	 * 
	 * @param persistentId
	 * @return
	 * @throws InterruptedException
	 * @throws QiniuException
	 */
	public synchronized boolean waitingProcessSuccess(String persistentId) throws InterruptedException, QiniuException {
		Thread.sleep(1000);
		int timeout = 5000;
		int records = 5;
		while (timeout > 0 && records-- > 0) {
			OperationStatus status = getOperaterManager().prefop(persistentId);
			if (status.code == 0) {
				return true;
			} else if (status.code == 1) {
			} else if (status.code == 2) {
			} else if (status.code == 3) {
				return false;
			} else if (status.code == 4) {
				return false;
			} else {
				return false;
			}
			Thread.sleep(1000);
			timeout = timeout - 1000;
		}
		return false;
	}
	
	/**
	 * <pre>
	 * 功能：获取视频信息
	 * </pre>
	 * @param basePath
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public SelfVideoInfo getVideoInfo(String basePath, String key) throws Exception {
		SelfVideoInfo info = new SelfVideoInfo();
		String result = HttpUtils.getGetResult(basePath + key + "?avinfo", "UTF-8");
		Type type = new TypeToken<VideoInfo>() {
		}.getType();
		VideoInfo avInfo = (VideoInfo) GsonUtils.getInstance().fromJson(result, type);
		info = avInfo.info();
		return info;
	}
	
	/**
	 * <pre>
	 * 功能：获取图片信息
	 * </pre>
	 * @param basePath
	 * @param key
	 * @return
	 * @throws Exception
	 */
	public ImageInfo getImageInfo(String basePath, String key) throws Exception {
		String result = HttpUtils.getGetResult(basePath + key + "?imageInfo", "UTF-8");
		Type type = new TypeToken<ImageInfo>() {
		}.getType();
		ImageInfo info = (ImageInfo) GsonUtils.getInstance().fromJson(result, type);
		return info;
	}
	
	/**
	 * <pre>
	 * 功能：删除key
	 * </pre>
	 * @param bucketName
	 * @param key
	 * @throws Exception
	 */
	public void deleteKey(String bucketName, String key) throws Exception {
		getBucketManager().delete(bucketName, key);
	}
	
	/**
	 * <pre>
	 * 功能：刷新指定路径的cdn缓存
	 * </pre>
	 * 
	 * @param dirPattern
	 * @throws Exception
	 */
	public void cleanCdn(String bucketName, String dirPattern) throws Exception {
		FileListIterator iter = getBucketManager().createFileListIterator(bucketName, dirPattern);
		if (iter.hasNext()) {
			FileInfo[] infoList = iter.next();
			for (FileInfo info : infoList) {
				String coverKey = info.key;
				flushCdn(coverKey);
			}
		}
	}
	
	/**
	 * <pre>
	 * 功能：刷新CDN
	 * </pre>
	 * 
	 * @param path
	 * @throws Exception
	 */
	public void flushCdn(String... path) throws Exception {
		getCdn().refreshUrls(path);
	}

	public String getAccessKey() {
		return accessKey;
	}

	public void setAccessKey(String accessKey) {
		this.accessKey = accessKey;
	}

	public String getSecretKey() {
		return secretKey;
	}

	public void setSecretKey(String secretKey) {
		this.secretKey = secretKey;
	}

	public String getPipeline() {
		return pipeline;
	}

	public void setPipeline(String pipeline) {
		this.pipeline = pipeline;
	}

	public Auth getAuth() {
		if(auth == null){
			synchronized (QiniuOSSTemplate.class) {
				if(auth == null){
					//密钥配置
					auth = Auth.create(accessKey, secretKey);
				}
			}
		}
		return auth;
	}

	public UploadManager getUploadManager() {
		if(uploadManager == null){
			synchronized (QiniuOSSTemplate.class) {
				if(uploadManager == null){
					//自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。
					Configuration c = new Configuration(Zone.autoZone());
					//创建上传对象
					uploadManager = new UploadManager(c);
				}
			}
		}
		return uploadManager;
	}

	public BucketManager getBucketManager() {
		if(bucketManager == null){
			synchronized (QiniuOSSTemplate.class) {
				if(bucketManager == null){
					//自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。
					Configuration c = new Configuration(Zone.autoZone());
					bucketManager = new BucketManager(getAuth(), c);
				}
			}
		}
		return bucketManager;
	}

	public OperationManager getOperaterManager() {
		if(operaterManager == null){
			synchronized (QiniuOSSTemplate.class) {
				if(operaterManager == null){
					//自动识别要上传的空间(bucket)的存储区域是华东、华北、华南。
					Configuration c = new Configuration(Zone.autoZone());
					operaterManager = new OperationManager(getAuth(), c);
				}
			}
		}
		return operaterManager;
	}

	public CdnManager getCdn() {
		if(cdn == null){
			synchronized (QiniuOSSTemplate.class) {
				if(cdn == null){
					cdn = new CdnManager(getAuth());					
				}
			}
		}
		return cdn;
	}
	
}
